﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net.NetworkInformation;
using System.Net;

using AsterNET.Manager;
using AsterNET.Manager.Action;
using AsterNET.Manager.Event;
using AsterNET.Manager.Response;
using AsterNET;

using DTO;
using DAL;
using System.Configuration;

namespace BLL
{
    public class CallMonitor
    {
        #region Private Properties
        private static ManagerConnection astCon;
        
        private UserInfoEntity us = new UserInfoEntity();
        private string _CurrentNumber;
        #endregion
        #region Public Properties
        public bool IncomingCall = false;
        public static IncomingCallHandler GetNum;
        public delegate void IncomingCallHandler(string incomingnum);
        #endregion

        System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

        public bool CheckAsteriskConnect(string Server, int Port, string UserID, string Pass)
        {
            try
            {
                astCon = new ManagerConnection(Server, Port, UserID, Pass);
                astCon.Login(5000);
                return true;
            }
            catch
            {
                astCon.Logoff();
                return false;
            }
            finally
            {
                astCon.Logoff();
            }
        }

        public void ConnectToAsterisk(string Server, int Port, string UserID, string Pass)
        {
            try
            {
                astCon = new ManagerConnection(Server, Port, UserID, Pass);
                // Goi cac event de thuc thi viec quan ly cuoc goi
            //    astCon.VarSet += astCon_VarSet;
                astCon.Cdr += astCon_Cdr;
            //    astCon.Hangup += astCon_Hangup;
                astCon.NewState += astCon_NewState;
                astCon.Login(5000);
            }
            catch
            {
                astCon.Logoff();
            }
        }

        public void DialNumber(string NumberToCall)
        {
            try
            {
                _CurrentNumber = NumberToCall;
                astCon.SendAction(new OriginateAction()
                {
                    Channel = "SIP/" + us.TelephoneNumber,
                    Exten = config.AppSettings.Settings["PrefixNum"].Value + NumberToCall,
                    Context = "from-internal",
                    Priority = "1",
                    CallerId = us.TelephoneNumber,
                    Timeout = 300000
                });
            }
            catch
            {

            }
            finally
            {
                _CurrentNumber = "";
            }
        }

        public void DoNotDisturb()
        {
            try
            {
                astCon.SendAction(new OriginateAction()
                {
                    Channel = "SIP/" + us.TelephoneNumber,
                    Exten = "*78",
                    Context = "from-internal",
                    Priority = "1",
                    CallerId = us.TelephoneNumber,
                    Timeout = 300000
                });
            }
            catch
            {

            }
        }

        public void ReadyToCall()
        {
            try
            {
                astCon.SendAction(new OriginateAction()
                {
                    Channel = "SIP/" + us.TelephoneNumber,
                    Exten = "*79",
                    Context = "from-internal",
                    Priority = "1",
                    CallerId = us.TelephoneNumber,
                    Timeout = 300000
                });
            }
            catch
            {

            }
        }


        private void astCon_Cdr(object sender, CdrEvent e)
        {            
            if (e.Destination == us.TelephoneNumber)
            {
                if (e.BillableSeconds > 5)
                {
                    DataTranferEntity dt = new DataTranferEntity();
                    if (dt.IsBusy == false)
                    {
                        RecordEntity re = new RecordEntity();
                        UpdateData up = new UpdateData();
                        if (e.UserField != null)
                        {
                            re.RecordLink = (e.UserField).Replace("audio:", "");
                            re.Duration = e.Duration;
                            re.DateReceived = e.DateReceived;
                            re.SourceDestination = e.Src.Trim();
                            re.ReceivedDestination = e.Destination.Trim();
                            re.Type = "IN";
                            re.User_ID = us.UserID;
                            up.UpdateCallRecord(re);
                        }

                        dt.IsBusy = true;
                    }
                }
            }
            else if (e.CallerId.Contains(us.TelephoneNumber))
            {
                if (e.BillableSeconds > 5)
                {
                    RecordEntity re = new RecordEntity();
                    UpdateData up = new UpdateData();
                    var prefixLength = config.AppSettings.Settings["PrefixNum"].Value.Length;
                    if (e.UserField != null)
                    {
                        re.RecordLink = (e.UserField).Replace("audio:", "");
                        re.Duration = e.Duration;
                        re.DateReceived = e.DateReceived;                        
                        re.SourceDestination = e.Src.Trim();
                        re.ReceivedDestination = e.Destination.Trim().Substring(prefixLength);
                        re.Type = "OUT";
                        re.User_ID = us.UserID;
                        up.UpdateCallRecord(re);
                    }
                }
            }
        }


        private void astCon_Hangup(object sender, HangupEvent e)
        {
            if (e.Connectedlinenum == us.TelephoneNumber && e.Cause == 16 && _Thread != null)
            {
                DoNotDisturb();
            }            
        }

        private void astCon_VarSet(object sender, VarSetEvent e)
        {        
            
        }      
        
        private void ShowInboundCall()
        {
            GetNum(_ConnectedLineNum);
        }

        private string _ConnectedLineNum;
        private static Thread _Thread;
        private void astCon_NewState(object sender, NewStateEvent e)
        {
            if (e.ChannelStateDesc != null)
            {
                if (e.Channel.ToUpper().StartsWith("SIP/" + us.TelephoneNumber))
                {
                    var thread = _Thread;                       
                    Thread.MemoryBarrier();
                    switch (e.ChannelStateDesc.ToLower())
                    {
                        case "ring":
                            if (GetNum != null && e.Connectedlinenum != us.TelephoneNumber)
                            {
                                if (
                                        thread == null ||
                                        thread.ThreadState == System.Threading.ThreadState.Stopped
                                  )
                                {
                                    _ConnectedLineNum = e.Connectedlinenum;
                                    var newThread = new Thread(ShowInboundCall);                                    
                                    newThread.IsBackground = true;
                                    newThread.Name = "ShowInboundCall";
                                    newThread.Start();
                                    Thread.MemoryBarrier();
                                    _Thread = newThread;
                                }
                                else
                                {
                                    try
                                    {
                                        
                                    }
                                    catch
                                    {

                                    }
                                }

                            }
                            break;
                        case "ringing":
                            if (GetNum != null && e.Connectedlinenum != us.TelephoneNumber)
                            {
                                if (
                                        thread == null ||
                                        thread.ThreadState == System.Threading.ThreadState.Stopped
                                  )
                                {
                                    _ConnectedLineNum = e.Connectedlinenum;
                                    var newThread = new Thread(ShowInboundCall);                                    
                                    newThread.IsBackground = true;
                                    newThread.Name = "ShowInboundCall";
                                    newThread.Start();
                                    Thread.MemoryBarrier();
                                    _Thread = newThread;
                                }
                                else
                                {

                                }

                            }
                            break;

                    }
                }
            }
        }

        public bool CheckCallMonitorServer(string address)
        {
            IPAddress ip = IPAddress.Parse(address);
            Ping pingsender = new Ping();
            PingReply reply = pingsender.Send(ip, 500);
            if (reply.Status == IPStatus.Success)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public void CloseThread()
        {            
            _Thread = null;
        }


    }
}
